#include "vi_dev_imp.h"
#include "vi_mgr.h"
#include "vi_pipe.h"
#include "guard.h"

#include "mpi_vi.h"

#include <stdio.h>

using namespace Json;
using namespace detu_infra;

namespace detu_media
{

constexpr const VI_DEV_ATTR_S ViDevImp::defaultDevAttr;

ViDevImp::ViDevImp(void)
	: ViDev(), fInited(false), fRef(0), fDevId(-1), fMutex(MUTEX_RECURSIVE)
{
	memset(&fDevAttr, 0, sizeof(VI_DEV_ATTR_S));
	memset(&fBindPipe, 0, sizeof(VI_DEV_BIND_PIPE_S));
}

ViDevImp::~ViDevImp(void)
{
	if (isStarted())
	{
		fRef = 1;
		stop();
	}

	if (isInited())
	{
		deinit();
	}
}

S_Result ViDevImp::init(const Json::Value& config)
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;
	do
	{
		fDevId = (config.isMember("devId") && config["devId"].isIntegral()) ? config["devId"].asInt() : -1;
		fDevAttr = defaultDevAttr;
		if (config.isMember("devAttr"))
		{
			const Value& devAttr = config["devAttr"];
#if 0
			if (devAttr.isMember("interfaceMode") && devAttr["interfaceMode"].isString())
			{
				const std::string& intfMode = devAttr["interfaceMode"].asString();
				if (0 == intfMode.compare("bt656"))
					fDevAttr.enIntfMode = VI_MODE_BT656;
				else if (0 == intfMode.compare("bt601"))
					fDevAttr.enIntfMode = VI_MODE_BT601;
				else if (0 == intfMode.compare("digital_camera"))
					fDevAttr.enIntfMode = VI_MODE_DIGITAL_CAMERA;
				else if (0 == intfMode.compare("bt1120_standard"))
					fDevAttr.enIntfMode = VI_MODE_BT1120_STANDARD;
				else if (0 == intfMode.compare("bt1120_interleaved"))
					fDevAttr.enIntfMode = VI_MODE_BT1120_INTERLEAVED;
				else if (0 == intfMode.compare("mipi"))
					fDevAttr.enIntfMode = VI_MODE_MIPI;
				else if (0 == intfMode.compare("mipi_yuv420_normal"))
					fDevAttr.enIntfMode = VI_MODE_MIPI_YUV420_NORMAL;
				else if (0 == intfMode.compare("mipi_yuv420_legacy"))
					fDevAttr.enIntfMode = VI_MODE_MIPI_YUV420_LEGACY;
				else if (0 == intfMode.compare("mipi_yuv422"))
					fDevAttr.enIntfMode = VI_MODE_MIPI_YUV422;
				else if (0 == intfMode.compare("lvds"))
					fDevAttr.enIntfMode = VI_MODE_LVDS;
				else if (0 == intfMode.compare("hispi"))
					fDevAttr.enIntfMode = VI_MODE_HISPI;
				else if (0 == intfMode.compare("slvs"))
					fDevAttr.enIntfMode = VI_MODE_SLVS;
			}

			if (devAttr.isMember("workMode") && devAttr["workMode"].isString())
			{
				const std::string& workMode = devAttr["workMode"].asString();
				if (0 == workMode.compare("1Multiplex"))
					fDevAttr.enWorkMode = VI_WORK_MODE_1Multiplex;
				else if (0 == workMode.compare("2Multiplex"))
					fDevAttr.enWorkMode = VI_WORK_MODE_2Multiplex;
				else if (0 == workMode.compare("3Multiplex"))
					fDevAttr.enWorkMode = VI_WORK_MODE_3Multiplex;
				else if (0 == workMode.compare("4Multiplex"))
					fDevAttr.enWorkMode = VI_WORK_MODE_4Multiplex;			
			}

			if (devAttr.isMember("componentMask") && devAttr["componentMask"].isArray())
			{
				const Value& compMask = devAttr["componentMask"];
				for (int i = 0; i < compMask.size() && i < VI_COMPMASK_NUM; i++)
					if (compMask[i].isIntegral())
						fDevAttr.au32ComponentMask[i] = compMask[i].asUInt();
	 		}

			if (devAttr.isMember("scanMode") && devAttr["scanMode"].isString())
			{
				const std::string& scanMode = devAttr["scanMode"].asString();
				if (0 == scanMode.compare("interlaced"))
					fDevAttr.enScanMode = VI_SCAN_INTERLACED;
				else if (0 == scanMode.compare("progressive"))
					fDevAttr.enScanMode = VI_SCAN_PROGRESSIVE;			
			}

			if (devAttr.isMember("adChnId") && devAttr["adChnId"].isArray())
			{
				const Value& adChnId = devAttr["adChnId"];
				for (int i = 0; i < adChnId.size() && i < VI_MAX_ADCHN_NUM; i++)
					if (adChnId[i].isIntegral())
						fDevAttr.as32AdChnId[i] = adChnId[i].asInt();
	 		}

			if (devAttr.isMember("dataSeq") && devAttr["dataSeq"].isString())
			{
				const std::string& dataSeq = devAttr["dataSeq"].asString();
				if (0 == dataSeq.compare("vuvu"))
					fDevAttr.enDataSeq = VI_DATA_SEQ_VUVU;
				else if (0 == dataSeq.compare("uvuv"))
					fDevAttr.enDataSeq = VI_DATA_SEQ_UVUV;
				else if (0 == dataSeq.compare("uyvy"))
					fDevAttr.enDataSeq = VI_DATA_SEQ_UYVY;
				else if (0 == dataSeq.compare("vyuy"))
					fDevAttr.enDataSeq = VI_DATA_SEQ_VYUY;	
				else if (0 == dataSeq.compare("yuyv"))
					fDevAttr.enDataSeq = VI_DATA_SEQ_YUYV;
				else if (0 == dataSeq.compare("yvyu"))
					fDevAttr.enDataSeq = VI_DATA_SEQ_YVYU;
			}
#endif
			if (devAttr.isMember("size"))
			{
				const Value& size = config["size"];
				if (size.isMember("width") && size["width"].isIntegral())
					fDevAttr.stSize.u32Width = size["width"].asUInt();

				if (size.isMember("height") && size["height"].isIntegral())
					fDevAttr.stSize.u32Height = size["height"].asUInt();
			}

			if (devAttr.isMember("basAttr"))
			{
				const Value& basAttr = config["basAttr"];
				if (basAttr.isMember("scaleAttr"))
				{
					const Value& scaleAttr = basAttr["scaleAttr"];
					if (scaleAttr.isMember("size"))
					{
						const Value& size = config["size"];
						if (size.isMember("width") && size["width"].isIntegral())
							fDevAttr.stBasAttr.stSacleAttr.stBasSize.u32Width = size["width"].asUInt();

						if (size.isMember("height") && size["height"].isIntegral())
							fDevAttr.stBasAttr.stSacleAttr.stBasSize.u32Height = size["height"].asUInt();
					}
				}				
			}
		}

		if (config.isMember("pipeToBind") && config["pipeToBind"].isArray())
		{
			const Value& pipes = config["pipeToBind"];
			int i = 0;
			ViMgr& viMgr = *ViMgr::instance();
			fBindPipe.u32Num = pipes.size();
			for (; i < pipes.size() && i < VI_MAX_PIPE_NUM; i++)
			{
				if (pipes[i].isString())
				{
					ViPipe* pipe = NULL;
					viMgr.getPipe(pipes[i].asString(), &pipe);
					if (pipe)
					{
						if (S_OK != pipe->getId(fBindPipe.PipeId[i]))
						{
							printf("get Id of pipe: %s failed! devId: %d\n", pipes[i].asCString(), fDevId);
							break;
						}
					}
					else
					{
						printf("pipe: %s not exist! devId: %d\n", pipes[i].asCString(), fDevId);
						break;
					}
				}
				else
				{
					printf("pipe: %d name not string! devId: %d\n", i, fDevId);
					break;
				}
			}

			if (i != pipes.size())
			{
				printf("init pipeToBind failed! devId: %d\n", fDevId);
				break;
			}
		}

		ret = S_OK;
		fInited = true;
	}
	while(0);

	return ret;
}

S_Result ViDevImp::deinit(void)
{
	Guard guard(fMutex);
	fDevId = -1;
	memset(&fDevAttr, 0, sizeof(VI_DEV_ATTR_S));
	memset(&fBindPipe, 0, sizeof(VI_DEV_BIND_PIPE_S));
	fInited = false;
	
	return S_OK;
}

bool ViDevImp::isInited(void)
{
	return fInited;
}

S_Result ViDevImp::start(void)
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;
	do
	{
		if (fRef < 0)
		{
			printf("start failed, fRef: %d < 0! devId: %d\n", fRef, fDevId);
			break;
		}
		
		if (fRef > 0)
		{
		    printf("start , fRef: %d > 0! devId: %d\n", fRef, fDevId);
			ret = S_OK;
			break;
		}

		if (!isInited())
		{
			printf("devId: %d not inited!\n", fDevId);
			break;
		}

		HI_S32 s32Ret = HI_MPI_VI_SetDevAttr(fDevId, &fDevAttr);
		if (HI_SUCCESS != s32Ret)
		{
			printf("HI_MPI_VI_SetDevAttr failed with ret: %#x, devId: %d\n", s32Ret, fDevId);
			break;
		}

		s32Ret = HI_MPI_VI_EnableDev(fDevId);
	    if (s32Ret != HI_SUCCESS)
	    {
	        printf("HI_MPI_VI_EnableDev failed with %#x, devId: %d\n", s32Ret, fDevId);
	        break;
	    }

		s32Ret = HI_MPI_VI_SetDevBindPipe(fDevId, &fBindPipe);
	    if (s32Ret != HI_SUCCESS)
	    {
	        printf("HI_MPI_VI_SetDevBindPipe failed with %#x, devId: %d\n", s32Ret, fDevId);
	        break;
	    }

		ret = S_OK;
	}
	while(0);

	if (S_OK == ret)
		fRef++;
	
	return ret;
}

S_Result ViDevImp::stop(void)
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;

	do
	{
		if (fRef <= 0)
		{
			printf("stop failed, fRef: %d < 0! devId: %d\n", fRef, fDevId);
			break;
		}
		
		if (fRef > 1)
		{
		    printf("stop , fRef: %d > 1! devId: %d\n", fRef, fDevId);
			ret = S_OK;
			break;
		}

		if (!isInited())
		{
			printf("devId: %d not inited!\n", fDevId);
			break;
		}
		
		HI_S32 s32Ret  = HI_MPI_VI_DisableDev(fDevId);

	    if (s32Ret != HI_SUCCESS)
	    {
	        printf("HI_MPI_VI_DisableDev failed with %#x, devId: %d\n", s32Ret, fDevId);
	        break;
	    }
	}
	while(0);

	if (S_OK == ret)
		fRef--;
	
	return ret;
}

bool ViDevImp::isStarted(void)
{
	return (fRef > 0);
}

S_Result ViDevImp::getId(int& id)
{
	id = fDevId;

	return S_OK;
}

}

